#pragma once

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
#include"Log.hpp"

#define BACKLOG 5

class TcpServer{
    private:
        int port;// 端口号
        int listen_sock;// 套接字
        static TcpServer *svr;
    private:
        TcpServer(int _port):port(_port),listen_sock(-1)
        {}
        TcpServer(const TcpServer &s){}
    public:
        static TcpServer *getinstance(int port)
        {
            static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;// 线程互斥锁，防止多线程时产生竞争
            if(nullptr == svr){
                pthread_mutex_lock(&lock);
                if(nullptr == svr){
                    svr = new TcpServer(port);// 创建tcpserver
                    svr -> InitServer();// 初始化
                }
                pthread_mutex_unlock(&lock);
            }
            return svr;
        }

        void InitServer()
        {
            Socket();
            Bind();
            Listen();
            LOG(INFO,"tcp_server init ... success");
        }

        void Socket()
        {
            listen_sock = socket(AF_INET,SOCK_STREAM,0);// 创建套接字
            if(listen_sock < 0){
                LOG(FATAL,"socket error!");
                exit(1);
            }
            int opt = 1;
            setsockopt(listen_sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));// 设置套接字选项，允许地址复用
            LOG(INFO,"create socket ... success!");
        }

        void Bind()
        {
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));// 清零
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;// 云服务器不能直接绑定公网IP

            if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){// 绑定失败
                LOG(FATAL,"bind error!");
                exit(2);
            }
            LOG(INFO,"bind socket ... success!");
        }

        void Listen()
        {
            if(listen(listen_sock,BACKLOG)<0){
                LOG(FATAL,"listen socket error!");
                exit(3);
            }
            LOG(INFO,"listen socket ... success!");
        }

        int Sock()
        {
            return listen_sock; 
        }

        ~TcpServer()
        {
            if(listen_sock >= 0) close(listen_sock);

        }
};

TcpServer* TcpServer::svr = nullptr;